package com.css.fxfzmh.base.dict.service.impl;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.afterturn.easypoi.excel.entity.result.ExcelImportResult;
import com.alibaba.fastjson.JSONObject;
import com.css.fxfzmh.base.cache.CacheService;
import com.css.fxfzmh.base.dict.DictDirExcelVerifyHandler;
import com.css.fxfzmh.base.dict.DictExcelVerifyHandler;
import com.css.fxfzmh.base.dict.DictItemExcelVerifyHandler;
import com.css.fxfzmh.base.dict.repository.DictRepository;
import com.css.fxfzmh.base.dict.repository.DictDirectoryRepository;
import com.css.fxfzmh.base.dict.repository.DictItemRepository;
import com.css.fxfzmh.base.dict.repository.entity.DictDirectoryEntity;
import com.css.fxfzmh.base.dict.repository.entity.DictEntity;
import com.css.fxfzmh.base.dict.repository.entity.DictItemEntity;
import com.css.fxfzmh.base.dict.service.DictService;
import com.css.fxfzmh.base.dict.viewobjects.DictDirExcelVO;
import com.css.fxfzmh.base.dict.viewobjects.DictExcelVO;
import com.css.fxfzmh.base.dict.viewobjects.DictItemExcelVO;
import com.css.fxfzmh.base.dict.viewobjects.DictQueryParams;
import com.css.fxfzmh.constants.YNEnum;
import com.css.fxfzmh.util.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.util.*;
import static com.css.fxfzmh.constants.CacheConstant.CACHE_SYS_KEY;

@Service
@Slf4j
public class DictImpl implements DictService {
    @Autowired
    DictRepository dictRepository;

    @Autowired
    DictItemRepository dictItemRepository;
    @Autowired
    CacheService cacheService;
    @Autowired
    DictDirectoryRepository dictDirectoryRepository;

    @Autowired
    DictExcelVerifyHandler dictExcelVerifyHandler;

    @Autowired
    DictItemExcelVerifyHandler dictItemExcelVerifyHandler;

    @Autowired
    DictDirExcelVerifyHandler dictDirExcelVerifyHandler;

    private static final String CACHE_DICT_ID_KEY = "dictId:";
    private static final String CACHE_DICT_CODE_KEY = "dictCode:";
    private static final String CACHE_DICT_CODE_LIST_KEY = "dictCodeList:";
    private static final String CACHE_DICT_ITEM_ID_KEY = "dictItemId:";
    private static final String CACHE_DICT_ITEM_CODE_KEY = "dictItemCode:";
    @Override
    public JSONObject queryDicts(DictQueryParams queryParams, int curPage, int pageSize){
        Page<DictEntity> dicts =  dictRepository.queryDicts(queryParams,curPage,pageSize);
        JSONObject jsonObject = PlatformPageUtils.formatPageData(dicts);
        return jsonObject;
    }
    @Override
    public DictEntity saveDict(DictEntity dictEntity){
        String uuid = UUIDGenerator.getUUID();
        dictEntity.setDictId(uuid);
        dictEntity.setIsValid(YNEnum.Y.toString());
        dictEntity.setCreateUser(PlatformSessionUtils.getUserId());
        dictEntity.setCreateTime(PlatformDateUtils.getCurrentTimestamp());
        dictRepository.saveDict(dictEntity);
        return dictEntity;
    }
    @Override
    public DictEntity updateDict(DictEntity dictEntity){
        dictEntity.setUpdateUser(PlatformSessionUtils.getUserId());
        dictEntity.setUpdateTime(PlatformDateUtils.getCurrentTimestamp());
        String dictCode  = dictRepository.findDictCodeByDictId(dictEntity.getDictId());
        dictRepository.saveDict(dictEntity);
        cacheService.delete(CACHE_SYS_KEY + CACHE_DICT_ID_KEY + dictEntity.getDictId());
        cacheService.delete(CACHE_SYS_KEY + CACHE_DICT_CODE_KEY + dictCode);
        return dictEntity;
    }
    @Override
    public DictEntity getDict(String id){
        DictEntity dict = null;
        dict = (DictEntity) cacheService.get(CACHE_SYS_KEY + CACHE_DICT_ID_KEY + id);
        if (PlatformObjectUtils.isEmpty(dict) ) {
            dict = dictRepository.findById(id);
            cacheService.set(CACHE_SYS_KEY + CACHE_DICT_ID_KEY + id, dict);
        }
        return dict;
    }

    @Override
    public void exportDict(HttpServletResponse response) {
        List<Map<String, Object>> sheetsList = new ArrayList<>();

        /***************字典目录****************/
        List<DictDirectoryEntity> dictDirectoryEntityList = dictDirectoryRepository.findAll();
        List<DictDirExcelVO> dictDirExcelVoList = new ArrayList<DictDirExcelVO>();
        dictDirectoryEntityList.forEach(e->{
            DictDirExcelVO dictDirExcelVo = new DictDirExcelVO();
            BeanUtils.copyProperties(e,dictDirExcelVo);
            dictDirExcelVoList.add(dictDirExcelVo);
        });

        Map<String, Object> dictDirDataMap = new HashMap<>(4);
        ExportParams dictDirExport = new ExportParams();
        dictDirExport.setSheetName("字典目录");
        dictDirDataMap.put("title", dictDirExport);
        dictDirDataMap.put("entity", DictDirExcelVO.class);
        dictDirDataMap.put("data", dictDirExcelVoList);
        sheetsList.add(dictDirDataMap);

        /****************字典目录***************/

        /***************字典****************/
        List<DictEntity> dictEntityList = dictRepository.findAll();
        List<DictExcelVO> dictExcelVoList = new ArrayList<DictExcelVO>();
        dictEntityList.forEach(e->{
            DictExcelVO dictExcelVo = new DictExcelVO();
            BeanUtils.copyProperties(e,dictExcelVo);
            dictExcelVoList.add(dictExcelVo);
        });
        Map<String, Object> dictDataMap = new HashMap<>(4);
        ExportParams dictExport = new ExportParams();
        dictExport.setSheetName("字典");
        dictDataMap.put("title", dictExport);
        dictDataMap.put("entity", DictExcelVO.class);
        dictDataMap.put("data", dictExcelVoList);
        sheetsList.add(dictDataMap);

        /****************字典***************/

        /***************字典项****************/
        List<DictItemEntity> dictItemEntityList = dictItemRepository.findAll();
        List<DictItemExcelVO> dictItemExcelVoList = new ArrayList<DictItemExcelVO>();
        dictItemEntityList.forEach(e->{
            DictItemExcelVO dictItemExcelVo = new DictItemExcelVO();
            BeanUtils.copyProperties(e,dictItemExcelVo);
            dictItemExcelVoList.add(dictItemExcelVo);
        });
        Map<String, Object> dictItemDataMap = new HashMap<>(4);
        ExportParams dictItemExport = new ExportParams();
        dictItemExport.setSheetName("字典项");
        dictItemDataMap.put("title", dictItemExport);
        dictItemDataMap.put("entity", DictItemExcelVO.class);
        dictItemDataMap.put("data", dictItemExcelVoList);
        sheetsList.add(dictItemDataMap);

        /****************字典项***************/

        Workbook workbook = ExcelExportUtil.exportExcel(sheetsList, ExcelType.HSSF);
        workbook.createCellStyle().setLocked(true);
        PlatformDownloadUtils.exportExcel(workbook,"数据字典.xls",response);
    }

    @Override
    public String uploadFile(MultipartFile file, HttpServletResponse response) {
        try {
            //这样写  excel 能兼容03和07
            InputStream is = file.getInputStream();
            Workbook hssfWorkbook = null;
            try {
                hssfWorkbook = new HSSFWorkbook(is);
            } catch (Exception ex) {
                is =file.getInputStream();
                hssfWorkbook = new XSSFWorkbook(is);
            }
            StringBuilder returnMsg = new StringBuilder();
            for (int numSheet = 0; numSheet < hssfWorkbook.getNumberOfSheets(); numSheet++) {

                ImportParams params = new ImportParams();
                params.setHeadRows(1);
                params.setStartSheetIndex(numSheet);
                params.setNeedVerify(true);
                //设置一个验证处理器
                Date createTime =PlatformDateUtils.getCurrentTimestamp();
                if(numSheet == 0){
                    params.setVerifyHandler(dictDirExcelVerifyHandler);
                    ExcelImportResult<DictDirExcelVO> result = ExcelImportUtil.importExcelMore(file.getInputStream(), DictDirExcelVO.class, params);//获到正确的数据，并把它们保存到数据库
                    List<DictDirExcelVO> list = result.getList();

                    //将完好数据保存到数据库

                    list.forEach(e->{
                        DictDirectoryEntity dictDirectoryEntity = new DictDirectoryEntity();
                        BeanUtils.copyProperties(e,dictDirectoryEntity);
                        dictDirectoryEntity.setCreateTime(createTime);
                        dictDirectoryEntity.setCreateUser(PlatformSessionUtils.getUserId());
                        dictDirectoryRepository.save(dictDirectoryEntity);
                    });
                    returnMsg.append("字典分类成功导入" + result.getList().size() + "条，失败" + result.getFailList().size() + "条<br/>");

                    //是否存在失败数据
                    if (result.isVerifyFail()) {
                        for (DictDirExcelVO entity : result.getFailList()) {
                            String msg = "";
                            returnMsg.append("第" + entity.getRowNum() + "行" + entity.getErrorMsg() + "<br/>");
                            returnMsg.append(msg);
                        }
                    }
                }else if(numSheet == 1){
                    params.setVerifyHandler(dictExcelVerifyHandler);
                    ExcelImportResult<DictExcelVO> result = ExcelImportUtil.importExcelMore(file.getInputStream(), DictExcelVO.class, params);//获到正确的数据，并把它们保存到数据库
                    List<DictExcelVO> list = result.getList();

                    //将完好数据保存到数据库
                    list.forEach(e->{
                        DictEntity dictEntity = new DictEntity();
                        BeanUtils.copyProperties(e,dictEntity);
                        dictEntity.setCreateTime(createTime);
                        dictEntity.setCreateUser(PlatformSessionUtils.getUserId());
                        dictRepository.saveDict(dictEntity);
                    });
                    returnMsg.append("字典成功导入" + result.getList().size() + "条，失败" + result.getFailList().size() + "条<br/>");

                    //是否存在失败数据
                    if (result.isVerifyFail()) {
                        for (DictExcelVO entity : result.getFailList()) {
                            String msg = "";
                            returnMsg.append("第" + entity.getRowNum() + "行" + entity.getErrorMsg() + "<br/>");
                            returnMsg.append(msg);
                        }
                    }
                }else if(numSheet ==2){
                    params.setVerifyHandler(dictItemExcelVerifyHandler);
                    ExcelImportResult<DictItemExcelVO> result = ExcelImportUtil.importExcelMore(file.getInputStream(), DictItemExcelVO.class, params);//获到正确的数据，并把它们保存到数据库
                    List<DictItemExcelVO> list = result.getList();

                    //将完好数据保存到数据库
                    list.forEach(e->{
                        DictItemEntity dictItemEntity = new DictItemEntity();
                        BeanUtils.copyProperties(e,dictItemEntity);
                        dictItemEntity.setCreateTime(createTime);
                        dictItemEntity.setCreateUser(PlatformSessionUtils.getUserId());
                        dictItemRepository.saveDictItem(dictItemEntity);
                    });
                    returnMsg.append("字典项成功导入" + result.getList().size() + "条，失败" + result.getFailList().size() + "条<br/>");

                    //是否存在失败数据
                    if (result.isVerifyFail()) {
                        for (DictItemExcelVO entity : result.getFailList()) {
                            String msg = "";
                            returnMsg.append("第" + entity.getRowNum() + "行" + entity.getErrorMsg() + "<br/>");
                            returnMsg.append(msg);
                        }
                    }
                }


            }
            return returnMsg.toString();
        } catch (Exception e) {
            e.printStackTrace();
            log.error(e.getMessage(), e);
            return "导入失败，请检查数据正确性";
        }
    }

    @Override
    public String getValueByDictCodeAndKey(String code, String key) {
        Object value = cacheService.get(CACHE_SYS_KEY + CACHE_DICT_CODE_LIST_KEY + code + key);
        if (PlatformObjectUtils.isEmpty(value) ) {
            value = dictItemRepository.getValueByDictCodeAndKey(code,key);
            if (!PlatformObjectUtils.isEmpty(key) ) {
                cacheService.set(CACHE_SYS_KEY + CACHE_DICT_CODE_LIST_KEY + code + key, value);
                return value.toString();
            }
        }
        return null;
    }

    @Override
    public String getKeyByDictCodeAndValue(String code, String value) {
        Object key = cacheService.get(CACHE_SYS_KEY + CACHE_DICT_CODE_LIST_KEY + code + value);
        if (PlatformObjectUtils.isEmpty(key) ) {
            key = dictItemRepository.getKeyByDictCodeAndValue(code,value);
            if (!PlatformObjectUtils.isEmpty(key) ) {
                cacheService.set(CACHE_SYS_KEY + CACHE_DICT_CODE_LIST_KEY + code + value, key);
                return key.toString();
            }
        }
        return null;
    }

    @Override
    public List<DictItemEntity> getValidDictItemsByDictCode(String code){
        List<DictItemEntity> dictItems = null;
        dictItems =  cacheService.range(CACHE_SYS_KEY + CACHE_DICT_CODE_LIST_KEY + code);
        if (PlatformObjectUtils.isEmpty(dictItems) ) {
            dictItems = dictItemRepository.findValidDictItemsByDictCode(code);
            cacheService.push(CACHE_SYS_KEY + CACHE_DICT_CODE_LIST_KEY + code, dictItems);
        }
        return dictItems;
    }
    @Transactional(rollbackFor = Exception.class )
    @Override
    public void deleteDicts(List<String> ids){
        deleteDictAndItemCache(ids);
        dictRepository.delete(ids);
        dictItemRepository.deleteByDictIds(ids);
    }
    private void deleteDictAndItemCache(List<String> ids){
        List<String> dictCacheKeys = new ArrayList<String>();
        List<DictEntity> dicts = dictRepository.findAllById(ids);
        List<DictItemEntity> dictItems = dictItemRepository.findDictItemByDictId(ids);
        if(PlatformObjectUtils.isNotEmpty(dicts)){
            for(DictEntity dict:dicts){
                dictCacheKeys.add(CACHE_SYS_KEY + CACHE_DICT_ID_KEY + dict.getDictId());
                dictCacheKeys.add(CACHE_SYS_KEY + CACHE_DICT_CODE_KEY + dict.getDictCode());
                dictCacheKeys.add(CACHE_SYS_KEY + CACHE_DICT_CODE_LIST_KEY + dict.getDictCode());
            }
        }
        if(PlatformObjectUtils.isNotEmpty(dictItems)){
            for(DictItemEntity dictItem:dictItems){
                dictCacheKeys.add(CACHE_SYS_KEY + CACHE_DICT_ITEM_ID_KEY + dictItem.getDictItemId());
                dictCacheKeys.add(CACHE_SYS_KEY + CACHE_DICT_ITEM_CODE_KEY + dictItem.getDictItemCode());
            }
        }
        cacheService.delete(dictCacheKeys);
    }
    private void deleteDictCache(List<String> ids){
        List<String> dictCacheKeys = new ArrayList<String>();
        List<DictEntity> dicts = dictRepository.findAllById(ids);
        if(PlatformObjectUtils.isNotEmpty(dicts)){
            for(DictEntity dict:dicts){
                dictCacheKeys.add(CACHE_SYS_KEY + CACHE_DICT_ID_KEY + dict.getDictId());
                dictCacheKeys.add(CACHE_SYS_KEY + CACHE_DICT_CODE_KEY + dict.getDictCode());
                dictCacheKeys.add(CACHE_SYS_KEY + CACHE_DICT_CODE_LIST_KEY + dict.getDictCode());
            }
        }
        cacheService.delete(dictCacheKeys);
    }
    @Override
    public boolean validateDictCode(String dictId,String dictCode){
        boolean isValid = false;
        DictEntity de = dictRepository.findOneByDictCode(dictCode);
        if(PlatformObjectUtils.isEmpty(de)){
            isValid = false;
        }else if(de.getDictId().equals(dictId)){
            isValid = true;
        }
        return isValid;
    }
    @Transactional(rollbackFor = Exception.class )
    @Override
    public void updateDicts(List<String> ids,String type){
        List<DictEntity> dictEntitys = dictRepository.findAllById(ids);
        for(DictEntity dictEntity:dictEntitys){
            if("1".equals(type)){
                dictEntity.setIsValid(YNEnum.Y.toString());
            }else{
                dictEntity.setIsValid(YNEnum.N.toString());
            }
            dictEntity.setUpdateUser(PlatformSessionUtils.getUserId());
            dictEntity.setUpdateTime(PlatformDateUtils.getCurrentTimestamp());
            dictRepository.saveDict(dictEntity);
        }
        deleteDictCache(ids);
    }
    @Override
    public List<String> getDictIdsByDictDirId(String dictDirId){
        List<DictEntity> dictList= dictRepository.findByDictDirId(dictDirId);
        List<String> strList = new ArrayList<>();
        if (dictList != null && dictList.size()>0){
            for (DictEntity dictEntity:dictList) {
                strList.add(dictEntity.getDictId());
            }
        }
        return strList;
    }

}
